package com.ddm.service.impl.vxImpl;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ddm.constant.MessageConstant;
import com.ddm.constant.VXConstant;
import com.ddm.context.BaseContext;
import com.ddm.dto.page.PageQueryDTO;
import com.ddm.dto.vxDTO.ExamDTO;
import com.ddm.dto.vxDTO.QuestionAnalysis;
import com.ddm.dto.vxDTO.QuestionDTO;
import com.ddm.entity.vxEntity.Exam;
import com.ddm.entity.vxEntity.ExamQuestion;
import com.ddm.entity.vxEntity.Score;
import com.ddm.entity.vxEntity.Question;
import com.ddm.entity.vxEntity.Test;
import com.ddm.entity.Bookmark;
import com.ddm.exception.DataErrorException;
import com.ddm.mapper.ExamMapper;
import com.ddm.mapper.ExamQuestionMapper;
import com.ddm.mapper.ScoreMapper;
import com.ddm.mapper.QuetsionsMapper;
import com.ddm.mapper.TestMapper;
import com.ddm.mapper.BookmarkMapper;
import com.ddm.result.PageResult;
import com.ddm.service.vxService.ExamService;
import com.ddm.service.vxService.BookmarkService;
import com.ddm.utils.BeanCopyUtil;
import com.ddm.utils.ExamHistoryCache;
import com.ddm.vo.vxVo.ExamVO;
import com.ddm.vo.vxVo.QuestionVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.RedisConnectionFailureException;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.math.BigDecimal;
/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author horizon
 * @since 2025-01-17
 */
@Service
@Slf4j
public class ExamServiceImpl extends ServiceImpl<ExamMapper, Exam> implements ExamService {


    @Autowired
    ExamMapper examMapper;

    @Autowired
    ExamQuestionMapper examQuestionMapper;

    @Autowired
    QuetsionsMapper quetsionsMapper;
    @Autowired
    ExamHistoryCache examHistoryCache;
    @Resource
    RedisTemplate<String,Object> redisTemplate;
    @Autowired
    StringRedisTemplate stringRedisTemplate;
    @Autowired
    TestMapper testMapper;
    @Autowired
    ScoreMapper scoreMapper;
    @Autowired
    private BookmarkService bookmarkService;
    @Autowired
    private BookmarkMapper bookmarkMapper;

    @Override
    @Transactional(rollbackFor = Exception.class) // 启用事务管理
    public String addExam(ExamDTO examDTO) {



        // 1. 检查考试名称唯一性
        LambdaQueryWrapper<Exam> nameQuery = new LambdaQueryWrapper<>();
        nameQuery.eq(Exam::getExamName, examDTO.getExamName());
        if (examMapper.selectOne(nameQuery) != null) {
            throw new DataErrorException(MessageConstant.ALREADY_EXISTS);
        }

        // 2. 校验试题有效性及标准ID一致性
        List<QuestionDTO> questionList = examDTO.getQuestionList();
        if (questionList != null && !questionList.isEmpty()) {
            for (QuestionDTO questionDTO : questionList) {
                // 检查试题是否存在
                if (quetsionsMapper.selectById(questionDTO.getId()) == null) {
                    throw new DataErrorException(MessageConstant.ERROR_DATA);
                }
            }
        }

        // 3. 插入考试主表
        if ((examDTO.getBeginTime()==null||examDTO.getEndTime()==null)) {
            throw new DataErrorException("开始时间与结束时间不能为空");
        }
        
        // 验证考试限时
        Integer duration = examDTO.getDuration();
        if (duration == null) {
            duration = VXConstant.DEFAULT_EXAM_DURATION; // 设置默认时长
        } else if (duration < VXConstant.MIN_EXAM_DURATION || duration > VXConstant.MAX_EXAM_DURATION) {
            throw new DataErrorException("考试限时必须在" + VXConstant.MIN_EXAM_DURATION + "-" + VXConstant.MAX_EXAM_DURATION + "分钟之间");
        }
        
        // 验证获奖比例
        validatePrizeRatios(examDTO);
        
        Exam exam = BeanCopyUtil.BeanCopy(examDTO, Exam.class);
        exam.setDuration(duration);
        
        // 设置默认获奖比例
        if (exam.getFirstPrizeRatio() == null) {
            exam.setFirstPrizeRatio(BigDecimal.valueOf(0.10)); // 默认10%
        }
        if (exam.getSecondPrizeRatio() == null) {
            exam.setSecondPrizeRatio(BigDecimal.valueOf(0.20)); // 默认20%
        }
        if (exam.getThirdPrizeRatio() == null) {
            exam.setThirdPrizeRatio(BigDecimal.valueOf(0.30)); // 默认30%
        }
        examMapper.insert(exam);
        LambdaQueryWrapper<Exam> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Exam::getExamName,exam.getExamName());
        exam.setId(examMapper.selectOne(wrapper).getId());
        // 4. 插入考试-试题关联表
        if (questionList != null && !questionList.isEmpty()) {
            for (QuestionDTO questionDTO : questionList) {
                ExamQuestion examQuestion = new ExamQuestion();
                examQuestion.setExamId(exam.getId());
                examQuestion.setQuestionId(questionDTO.getId());
                examQuestionMapper.insert(examQuestion);
            }
        }
        return "添加成功";
    }

    @Override
    public PageResult getExamList(PageQueryDTO pageQueryDTO) {
        LambdaQueryWrapper<Exam> wrapper = new LambdaQueryWrapper<>();
        Page<Exam> page = new Page<>(pageQueryDTO.getPage(),pageQueryDTO.getPageSize());
        wrapper.orderByAsc(Exam::getId);
        examMapper.selectPage(page, wrapper);
        long total = page.getTotal();
        List<Exam> records = page.getRecords();
        PageResult pageResult = new PageResult(total,records);
        return pageResult;
    }

    /**
     * 随机获取下一题
     * @param examId
     * @return
     */
    @Override
    public QuestionVO getNextQuetsion(Long examId) {
        String examQuestionKey = VXConstant.EXAM_QUESTIONS_KEY + examId;
        List<Long> questionList;
        
        try {
            String cachedIds = (String) redisTemplate.opsForValue().get(examQuestionKey);
            // 使用Hutool转换
            questionList = Optional.ofNullable(cachedIds)
                    .map(json -> {
                        try {
                            return JSONUtil.toList(json, Long.class);
                        } catch (Exception e) {
                            log.warn("缓存数据解析失败: " + e.getMessage());
                            return null;
                        }
                    })
                    .orElseThrow(() -> new DataErrorException("试题未初始化"));
        } catch (RedisConnectionFailureException e) {
            log.warn("Redis连接失败，从数据库查询题目列表: " + e.getMessage());
            // Redis连接失败时，从数据库查询
            LambdaQueryWrapper<ExamQuestion> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(ExamQuestion::getExamId, examId);
            List<ExamQuestion> examQuestions = examQuestionMapper.selectList(queryWrapper);
            questionList = examQuestions.stream()
                    .map(ExamQuestion::getQuestionId)
                    .collect(Collectors.toList());
            if (questionList.isEmpty()) {
                throw new DataErrorException("试题未初始化");
            }
        }

        if (questionList == null || questionList.isEmpty()){
            throw new DataErrorException(MessageConstant.ERROR_DATA);
        }
        List<Long> visited = examHistoryCache.getHistory(BaseContext.getCurrentId(), examId);
        //未访问的题目
        List<Long> remainIds = questionList.stream().filter(id -> !visited.contains(id)).collect(Collectors.toList());
        if (remainIds.isEmpty()){
            throw new DataErrorException("所有题目访问完毕");
        }
        //随机选择下一题
        int randomIndex = ThreadLocalRandom.current().nextInt(remainIds.size());
        Long nextQuestionID = remainIds.get(randomIndex);

        //记录到redis
        examHistoryCache.pushQuestionHistory(BaseContext.getCurrentId(),examId,nextQuestionID);

        Question nextQuestion = quetsionsMapper.selectById(nextQuestionID);
        return BeanCopyUtil.BeanCopy(nextQuestion,QuestionVO.class);
    }

    /**
     * 获取上一题
     * @param examId
     * @return
     */
    @Override
    public QuestionVO getPreviousQuestion(Long examId) {
        Long userId = BaseContext.getCurrentId();
        //获取当前题和上一题
        Long previousQuestionId = examHistoryCache.getPreviousQuestionId(userId, examId);
        if (previousQuestionId == null){
            throw  new DataErrorException("没有上一题");
        }

        //移除当前题目
        examHistoryCache.popLatestQuestion(userId, examId);

        Question question = quetsionsMapper.selectById(previousQuestionId);
        if (question == null){
            throw  new DataErrorException(MessageConstant.ERROR_DATA);
        }

        return BeanCopyUtil.BeanCopy(question,QuestionVO.class);
    }

    @Override
    public void startExam(Long id) {
        Exam exam = examMapper.selectById(id);
        if (exam==null){
            throw new DataErrorException(MessageConstant.NULL_DATA);
        }
        //缓存答案到Redis中
        LambdaQueryWrapper<ExamQuestion> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ExamQuestion::getExamId, exam.getId());
        List<ExamQuestion> examQuestions = examQuestionMapper.selectList(wrapper);
        List<Long> questionIds = examQuestions.stream().map(ExamQuestion::getQuestionId).collect(Collectors.toList());
        List<Question> questions = quetsionsMapper.selectBatchIds(questionIds);

        String cacheKey = String.format(VXConstant.QUESTION_ANSWER_KEY, exam.getId());
        try {
            for (Question question : questions) {
                stringRedisTemplate.opsForHash().put(cacheKey,String.valueOf(question.getId()),question.getAnswer());
            }
            stringRedisTemplate.expire(cacheKey,VXConstant.CACHE_TTL,TimeUnit.HOURS);
        }catch (RedisConnectionFailureException e){
            log.warn("Redis连接失败，跳过答案缓存: " + e.getMessage());
            // Redis连接失败时，跳过缓存，不影响考试功能
        }catch (Exception e){
            log.error("缓存考试答案失败: " + e.getMessage());
            // 其他异常不影响考试功能
        }
    }

    @Override
    public List<QuestionAnalysis> analysisQuestion(Long examId) {
        // 1. 查询考试关联的题目ID列表
        LambdaQueryWrapper<ExamQuestion> examQuestionQuery = new LambdaQueryWrapper<>();
        examQuestionQuery.eq(ExamQuestion::getExamId, examId)
                .select(ExamQuestion::getQuestionId);
        List<Long> questionIds = examQuestionMapper.selectList(examQuestionQuery)
                .stream()
                .map(ExamQuestion::getQuestionId)
                .collect(Collectors.toList());
        if (questionIds.isEmpty()) {
          throw new DataErrorException(MessageConstant.ERROR_DATA);
        }
        // 2. 批量查询题目详情
        List<Question> questions = quetsionsMapper.selectBatchIds(questionIds);
        if (questions.isEmpty()) {
            throw new DataErrorException(MessageConstant.ERROR_DATA);
        }

        // 3. 批量查询用户答题记录（减少数据库访问次数）
        Long userId = BaseContext.getCurrentId();
        LambdaQueryWrapper<Test> testQuery = new LambdaQueryWrapper<>();
        testQuery.eq(Test::getExamId, examId)
                .eq(Test::getUserId, userId)
                .in(Test::getQuestionId, questionIds)
                .select(Test::getQuestionId, Test::getUserAnswer);
        List<Test> tests = testMapper.selectList(testQuery);
        Map<Long, String> userAnswerMap = tests.stream()
                .collect(Collectors.toMap(Test::getQuestionId, Test::getUserAnswer, (v1, v2) -> v1));

        // 4. 构建分析结果
        List<QuestionAnalysis> result = new ArrayList<>();
        for (Question question : questions) {
            QuestionAnalysis analysis = new QuestionAnalysis();
            analysis.setQuestionId(question.getId());
            analysis.setQuestionContent(question.getQuestionContent());
            analysis.setQuestionAnalysis(question.getQuestionAnalysis());
            analysis.setCorrectAnswer(question.getAnswer());

            // 重新计算是否答对
            String userAnswer = userAnswerMap.get(question.getId());
            boolean isCorrect = false;
            if (userAnswer != null && !userAnswer.trim().isEmpty()) {
                isCorrect = normalizeAnswer(userAnswer).equals(normalizeAnswer(question.getAnswer()));
            }
            analysis.setIsCorrect(isCorrect);
            analysis.setUserAnswer(userAnswer != null ? userAnswer : "");

            result.add(analysis);
        }

        return result;
    }

    /**
     * 标准化答案格式
     */
    private String normalizeAnswer(String answer) {
        if (answer == null || answer.trim().isEmpty()) {
            return "";
        }
        // 处理无逗号的答案（如 "ACD" → "A,C,D"）
        String normalized = answer.replaceAll("([A-Za-z])", "$1,")  // 字母后加逗号
                .replaceAll(",+,", ",")          // 去重逗号
                .replaceAll("^,|,$", "");        // 去除首尾逗号
        return Arrays.stream(normalized.split(","))
                .map(String::trim)
                .map(String::toUpperCase)
                .sorted()
                .collect(Collectors.joining(","));
    }


    @Override
    public List<ExamVO> getContestInfo() {
        // 查询所有竞赛，按创建时间倒序
        LambdaQueryWrapper<Exam> wrapper = new LambdaQueryWrapper<>();
        wrapper.orderByDesc(Exam::getCreateTime);
        List<Exam> contests = examMapper.selectList(wrapper);
        
        if (contests.isEmpty()) {
            return Collections.emptyList();
        }
        
        List<ExamVO> examVOList = new ArrayList<>();
        LocalDateTime now = LocalDateTime.now();
        
        // 获取当前用户ID
        Long currentUserId = BaseContext.getCurrentId();
        
        for (Exam contest : contests) {
        ExamVO examVO = BeanCopyUtil.BeanCopy(contest, ExamVO.class);
            
            // 根据时间判断竞赛状态
            String status = determineContestStatus(contest.getBeginTime(), contest.getEndTime(), now);
            examVO.setStatus(status);
            
            // 判断用户是否已参与过该竞赛
            boolean hasParticipated = false;
            // 判断用户是否已报名该竞赛
            boolean hasRegistered = false;
            if (currentUserId != null) {
                // 检查是否已参与（已完成考试）
                LambdaQueryWrapper<Score> scoreQuery = new LambdaQueryWrapper<>();
                scoreQuery.eq(Score::getUserId, currentUserId)
                         .eq(Score::getExamId, contest.getId());
                Score userScore = scoreMapper.selectOne(scoreQuery);
                hasParticipated = userScore != null;
                
                // 检查是否已报名（收藏即报名）
                hasRegistered = bookmarkService.checkExamRegistration(currentUserId, contest.getId());
            }
            examVO.setHasParticipated(hasParticipated);
            examVO.setHasRegistered(hasRegistered);
            
            // 获取竞赛题目数量（不包含详细题目信息，提高性能）
        String examQuestionKey = VXConstant.EXAM_QUESTIONS_KEY + contest.getId();
        List<Long> questionIDs = Collections.emptyList();
            
        try {
            if (!redisTemplate.hasKey(examQuestionKey)) {
                // 缓存未命中时查询数据库
                LambdaQueryWrapper<ExamQuestion> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(ExamQuestion::getExamId, contest.getId());
                List<ExamQuestion> examQuestions = examQuestionMapper.selectList(queryWrapper);
                questionIDs = examQuestions.stream()
                        .map(ExamQuestion::getQuestionId)
                        .collect(Collectors.toList());

                // 缓存非空结果
                if (!questionIDs.isEmpty()) {
                    try {
                        String jsonStr = JSONUtil.toJsonStr(questionIDs);
                        redisTemplate.opsForValue().set(
                                examQuestionKey,
                                jsonStr,
                                VXConstant.CACHE_TTL,
                                TimeUnit.HOURS
                        );
                    } catch (RedisConnectionFailureException e) {
                        log.warn("Redis缓存写入失败，但不影响功能使用: " + e.getMessage());
                    }
                }
            } else {
                // 缓存命中时直接读取
                String cachedIds = (String) redisTemplate.opsForValue().get(examQuestionKey);
                if (StrUtil.isNotBlank(cachedIds)) {
                    try {
                        questionIDs = JSONUtil.toList(cachedIds, Long.class);
                    } catch (Exception e) {
                        log.warn("缓存数据解析失败，重新查询数据库: " + e.getMessage());
                        // 解析失败时重新查询数据库
                        LambdaQueryWrapper<ExamQuestion> queryWrapper = new LambdaQueryWrapper<>();
                        queryWrapper.eq(ExamQuestion::getExamId, contest.getId());
                        List<ExamQuestion> examQuestions = examQuestionMapper.selectList(queryWrapper);
                        questionIDs = examQuestions.stream()
                                .map(ExamQuestion::getQuestionId)
                                .collect(Collectors.toList());
                    }
                }
            }
        } catch (RedisConnectionFailureException e) {
            log.warn("Redis连接失败，直接从数据库查询: " + e.getMessage());
            // Redis连接失败时，直接从数据库查询
            LambdaQueryWrapper<ExamQuestion> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(ExamQuestion::getExamId, contest.getId());
            List<ExamQuestion> examQuestions = examQuestionMapper.selectList(queryWrapper);
            questionIDs = examQuestions.stream()
                    .map(ExamQuestion::getQuestionId)
                    .collect(Collectors.toList());
        }

            // 设置题目列表为空（只返回竞赛基本信息，不包含详细题目）
            examVO.setQuestionList(Collections.emptyList());
            
            // 获取统计信息
            ExamStatistics statistics = getExamStatistics(contest.getId());
            examVO.setQuestionCount(statistics.getQuestionCount());
            examVO.setRegisteredCount(statistics.getRegisteredCount());
            examVO.setParticipatedCount(statistics.getParticipatedCount());
            
            examVOList.add(examVO);
        }
        
        // 按状态排序：进行中（时间临近越前）、即将开始、已结束
        examVOList.sort((exam1, exam2) -> {
            int priority1 = getStatusPriority(exam1.getStatus());
            int priority2 = getStatusPriority(exam2.getStatus());
            
            if (priority1 != priority2) {
                return Integer.compare(priority1, priority2);
            }
            
            // 同一状态内按时间排序
            if ("进行中".equals(exam1.getStatus())) {
                // 进行中的按结束时间升序（越早结束越靠前）
                return exam1.getEndTime().compareTo(exam2.getEndTime());
            } else if ("即将开始".equals(exam1.getStatus())) {
                // 即将开始的按开始时间升序（越早开始越靠前）
                return exam1.getBeginTime().compareTo(exam2.getBeginTime());
            } else {
                // 已结束的按结束时间降序（越晚结束越靠前）
                return exam2.getEndTime().compareTo(exam1.getEndTime());
            }
        });
        
        return examVOList;
    }
    
    /**
     * 根据开始时间和结束时间判断竞赛状态
     * @param beginTime 开始时间
     * @param endTime 结束时间
     * @param now 当前时间
     * @return 竞赛状态
     */
    private String determineContestStatus(LocalDateTime beginTime, LocalDateTime endTime, LocalDateTime now) {
        if (now.isBefore(beginTime)) {
            return "即将开始";
        } else if (now.isAfter(endTime)) {
            return "已结束";
        } else {
            return "进行中";
        }
    }

    /**
     * 获取状态优先级，数字越小优先级越高
     * @param status 竞赛状态
     * @return 优先级
     */
    private int getStatusPriority(String status) {
        switch (status) {
            case "进行中":
                return 1;
            case "即将开始":
                return 2;
            case "已结束":
                return 3;
            default:
                return 4;
        }
    }

    @Override
    public ExamVO getExamDetail(Long examId) {
        // 1. 查询考试基本信息
        Exam exam = examMapper.selectById(examId);
        if (exam == null) {
            throw new DataErrorException("考试不存在");
        }

        // 2. 转换为VO
        ExamVO examVO = BeanCopyUtil.BeanCopy(exam, ExamVO.class);

        // 3. 添加竞赛状态
        LocalDateTime now = LocalDateTime.now();
        String status = determineContestStatus(exam.getBeginTime(), exam.getEndTime(), now);
        examVO.setStatus(status);

        // 4. 查询考试关联的题目
        LambdaQueryWrapper<ExamQuestion> examQuestionQuery = new LambdaQueryWrapper<>();
        examQuestionQuery.eq(ExamQuestion::getExamId, examId)
                .select(ExamQuestion::getQuestionId);
        List<Long> questionIds = examQuestionMapper.selectList(examQuestionQuery)
                .stream()
                .map(ExamQuestion::getQuestionId)
                .collect(Collectors.toList());

        if (!questionIds.isEmpty()) {
            // 5. 批量查询题目详情
            List<Question> questions = quetsionsMapper.selectBatchIds(questionIds);
            List<QuestionVO> questionVOS = BeanCopyUtil.BeanCopyList(questions, QuestionVO.class);
            examVO.setQuestionList(questionVOS);
        } else {
            examVO.setQuestionList(Collections.emptyList());
        }

        // 6. 获取统计信息
        ExamStatistics statistics = getExamStatistics(examId);
        examVO.setQuestionCount(statistics.getQuestionCount());
        examVO.setRegisteredCount(statistics.getRegisteredCount());
        examVO.setParticipatedCount(statistics.getParticipatedCount());

        return examVO;
    }

    @Override
    public ExamStatistics getExamStatistics(Long examId) {
        // 1. 查询题目总数
        LambdaQueryWrapper<ExamQuestion> questionQuery = new LambdaQueryWrapper<>();
        questionQuery.eq(ExamQuestion::getExamId, examId);
        Integer questionCount = examQuestionMapper.selectCount(questionQuery);

        // 2. 查询报名人数（通过bookmark表）
        LambdaQueryWrapper<Bookmark> registeredQuery = new LambdaQueryWrapper<>();
        registeredQuery.eq(Bookmark::getExam_id, examId);
        Integer registeredCount = bookmarkMapper.selectCount(registeredQuery);

        // 3. 查询参与人数（通过score表，已完成考试的用户）
        LambdaQueryWrapper<Score> participatedQuery = new LambdaQueryWrapper<>();
        participatedQuery.eq(Score::getExamId, examId);
        Integer participatedCount = scoreMapper.selectCount(participatedQuery);

        return new ExamStatistics(questionCount, registeredCount, participatedCount);
    }

    /**
     * 验证获奖比例
     * @param examDTO 考试DTO
     */
    private void validatePrizeRatios(ExamDTO examDTO) {
        BigDecimal firstRatio = examDTO.getFirstPrizeRatio();
        BigDecimal secondRatio = examDTO.getSecondPrizeRatio();
        BigDecimal thirdRatio = examDTO.getThirdPrizeRatio();
        
        // 如果设置了获奖比例，则进行验证
        if (firstRatio != null || secondRatio != null || thirdRatio != null) {
            // 验证比例范围（0-1之间）
            if (firstRatio != null && (firstRatio.compareTo(BigDecimal.ZERO) < 0 || firstRatio.compareTo(BigDecimal.ONE) > 0)) {
                throw new DataErrorException("一等奖比例必须在0-1之间");
            }
            if (secondRatio != null && (secondRatio.compareTo(BigDecimal.ZERO) < 0 || secondRatio.compareTo(BigDecimal.ONE) > 0)) {
                throw new DataErrorException("二等奖比例必须在0-1之间");
            }
            if (thirdRatio != null && (thirdRatio.compareTo(BigDecimal.ZERO) < 0 || thirdRatio.compareTo(BigDecimal.ONE) > 0)) {
                throw new DataErrorException("三等奖比例必须在0-1之间");
            }
            
            // 验证总比例不超过100%
            BigDecimal totalRatio = BigDecimal.ZERO;
            if (firstRatio != null) totalRatio = totalRatio.add(firstRatio);
            if (secondRatio != null) totalRatio = totalRatio.add(secondRatio);
            if (thirdRatio != null) totalRatio = totalRatio.add(thirdRatio);
            
            if (totalRatio.compareTo(BigDecimal.ONE) > 0) {
                throw new DataErrorException("获奖比例总和不能超过100%");
            }
        }
    }

}
